﻿// ======================================================================
//   
//           Copyright (C) 2019-2020 湖南心莱信息科技有限公司    
//           All rights reserved
//   
//           filename : ApiBase.cs
//           description :
//   
//           created by 雪雁 at  2019-03-13 10:03
//           Mail: wenqiang.li@xin-lai.com
//           QQ群：85318032（技术交流）
//           Blog：http://www.cnblogs.com/codelove/
//           GitHub：https://github.com/xin-lai
//           Home：http://xin-lai.com
//   
// ======================================================================

using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Monkey.Dingtalk.SDK.Token;
using Newtonsoft.Json;
using RestSharp;

namespace Monkey.Dingtalk.SDK
{
  public abstract class ApiBase
  {
    private const          string           AccessTokenString = "{ACCESS_TOKEN}";
    private const          string           BaseApiUrl        = "https://oapi.dingtalk.com/";
    private readonly       ILogger<ApiBase> _logger;
    private readonly       IServiceProvider _serviceProvider;
    public static readonly RestClient       Client = new RestClient(BaseApiUrl);

    protected ApiBase(ILogger<ApiBase> logger, IServiceProvider serviceProvider) {
      _logger          = logger;
      _serviceProvider = serviceProvider;
    }

    protected virtual async Task<T> Get<T>(string resourceUrl, Dictionary<string, string> queryParameters = null)
      where T : ApiResultBase, new() {
      resourceUrl = await SetAccessToken(resourceUrl);
      _logger.LogDebug($"GET {BaseApiUrl}{resourceUrl}");
      var request = new RestRequest(resourceUrl, Method.GET);
      request.AddHeader("cache-control", "no-cache");
      if (queryParameters != null && queryParameters.Count > 0) {
        foreach (var par in queryParameters) {
          request.AddQueryParameter(par.Key, par.Value, true);
        }
      }

      return await ReturnDataAsync<T>(Client, request);
    }

    protected virtual async Task<T> Post<T>(string resourceUrl, object data = null) where T : ApiResultBase, new() {
      resourceUrl = await SetAccessToken(resourceUrl);
      
      _logger.LogDebug(
        $"POST {BaseApiUrl}{resourceUrl}{(data != null ? Environment.NewLine + JsonConvert.SerializeObject(data) : string.Empty)}"
      );

      var request = new RestRequest(resourceUrl, Method.POST);
      request.AddHeader("cache-control", "no-cache");
      if (data != null) {
        request.AddJsonBody(data);
      }

      return await ReturnDataAsync<T>(Client, request);
    }

    private async Task<string> SetAccessToken(string url) {
      if (url.IndexOf(AccessTokenString, StringComparison.CurrentCultureIgnoreCase) == -1) {
        return url;
      }

      var tokenManager = _serviceProvider.GetService<TokenManager>();
      var token        = await tokenManager.GetToken();
      url = url.Replace(AccessTokenString, token, StringComparison.CurrentCultureIgnoreCase);
      _logger.LogDebug("Url Token 更新成功...");
      return url;
    }

    private async Task<T> ReturnDataAsync<T>(RestClient client, RestRequest request) where T : ApiResultBase, new() {
      var response = await client.ExecuteAsync<T>(request);
      _logger.LogDebug($"{response.StatusCode} {response.Content}");
      if (response.StatusCode != HttpStatusCode.OK) throw new Exception("请求钉钉接口失败", response.ErrorException);
      var data = JsonConvert.DeserializeObject<T>(response.Content);
      if (!data.IsSuccess()) {
        throw new Exception($"钉钉接口错误，code： {data.ErrorMessage}，message： {data.ErrorCode}");
      }
      return data;
    }
  }
}